package me.flyray.bsin.server.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch.core.DeleteRequest;
import co.elastic.clients.elasticsearch.core.IndexRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.UpdateRequest;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import co.elastic.clients.elasticsearch.core.search.TotalHitsRelation;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.elasticsearch.transform.Settings;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.util.Mapping;
import jakarta.json.stream.JsonGenerator;
import lombok.extern.slf4j.Slf4j;
import me.flyray.bsin.context.BsinServiceContext;
import me.flyray.bsin.domain.entity.AgentCard;
import me.flyray.bsin.domain.entity.KnowledgeBaseFile;
import me.flyray.bsin.facade.service.ElasticsearchService;
import org.apache.commons.collections.MapUtils;
import org.apache.shenyu.client.apache.dubbo.annotation.ShenyuDubboService;
import org.apache.shenyu.client.apidocs.annotations.ApiDoc;
import org.apache.shenyu.client.apidocs.annotations.ApiModule;
import org.apache.shenyu.client.dubbo.common.annotation.ShenyuDubboClient;
import org.elasticsearch.client.RequestOptions;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@ShenyuDubboService(path = "/search", timeout = 6000)
@ApiModule(value = "search")
public class ElasticsearchServiceImpl implements ElasticsearchService {

    private final ElasticsearchClient elasticsearchClient;

    public ElasticsearchServiceImpl(ElasticsearchClient elasticsearchClient) {
        this.elasticsearchClient = elasticsearchClient;
    }

    @ApiDoc(desc = "createIndex")
    @ShenyuDubboClient("/createIndex")
    @Override
    public void createIndex(Map<String, Object> requestMap) throws IOException {
        String indexName = MapUtils.getString(requestMap, "indexName");

        AgentCard agentCard = new AgentCard();
        // 定义 Mapping
        TypeMapping mappings = TypeMapping.of(m -> m
                        .properties("serialNo", p -> p.keyword(kp -> kp)) // 使用 keyword 构建器
                        .properties("name", p -> p.text(tp -> tp))
                        .properties("description", p -> p.text(tp -> tp))
                        .properties("created_at", p -> p.date(dp -> dp))
                // 可以添加更多字段和属性
        );

        // 定义 Settings
        IndexSettings settings = IndexSettings.of(s -> s
                        .numberOfShards("3")
                        .numberOfReplicas("1")
                // 可以添加更多索引设置，例如分析器等
        );

        CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder()
                .index(indexName)
                .mappings(mappings)
                .settings(settings)
                .build();

        elasticsearchClient.indices().create(createIndexRequest);
    }

    @ApiDoc(desc = "deleteIndex")
    @ShenyuDubboClient("/deleteIndex")
    @Override
    public void deleteIndex(Map<String, Object> requestMap) throws IOException {
        String indexName = MapUtils.getString(requestMap, "indexName");
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest.Builder()
                .index(indexName)
                .build();
        elasticsearchClient.indices().delete(deleteIndexRequest);
    }

    @ApiDoc(desc = "getIndex")
    @ShenyuDubboClient("/getIndex")
    @Override
    public Map<String, Object> getIndex(Map<String, Object> requestMap) throws IOException {
        String indexName = MapUtils.getString(requestMap, "indexName");
        GetIndexRequest getIndexRequest = new GetIndexRequest.Builder()
                .index(indexName)
                .build();
        GetIndexResponse getIndexResponse = elasticsearchClient.indices().get(getIndexRequest);

        Map<String, Object> result = new HashMap<>();

        // 获取别名映射
        // Now you can extract information from getIndexResponse
        // Example: Get index mappings
        TypeMapping mappings = getIndexResponse.get(indexName).mappings();
        result.put("mappings", serializeToJson(mappings));
        System.out.println("Mappings for '" + indexName + "': " + mappings);
        // Example: Get index settings
        IndexSettings settings = getIndexResponse.get(indexName).settings();
        result.put("settings", serializeToJson(settings));
        System.out.println("Settings for '" + indexName + "': " + settings);
        // Example: Get aliases for the index
        Map<String, Alias> aliases = getIndexResponse.get(indexName).aliases();
        result.put("aliases", aliases);
        System.out.println("Aliases for '" + indexName + "': " + aliases);

        return result;
    }

    @ApiDoc(desc = "add")
    @ShenyuDubboClient("/add")
    @Override
    public void add(Map<String, Object> requestMap) throws IOException {
        String indexName = MapUtils.getString(requestMap, "indexName");
        AgentCard agentCard = BsinServiceContext.bisId(AgentCard.class, requestMap);
        IndexRequest<AgentCard> req = IndexRequest.of(builder->
                builder.index(indexName)
//                        .id("")
                        .document(agentCard));
        elasticsearchClient.index(req);

    }

    @ApiDoc(desc = "edit")
    @ShenyuDubboClient("/edit")
    @Override
    public void edit(Map<String, Object> requestMap) throws IOException {
        String indexName = MapUtils.getString(requestMap, "indexName");
        AgentCard agentCard = BsinServiceContext.bisId(AgentCard.class, requestMap);

        UpdateRequest<AgentCard,AgentCard> req;
        req = UpdateRequest.of(
                b-> b.index(indexName)
                        .id("")
                        .doc(agentCard)
        );
        elasticsearchClient.update(req,KnowledgeBaseFile.class);

    }

    @ApiDoc(desc = "delete")
    @ShenyuDubboClient("/delete")
    @Override
    public void delete(Map<String, Object> requestMap) throws IOException {
        String indexName = MapUtils.getString(requestMap, "indexName");
        DeleteRequest req = DeleteRequest.of(
                b-> b.index(indexName)
                .id("1")
        );
        elasticsearchClient.delete(req);
    }

    @ApiDoc(desc = "search")
    @ShenyuDubboClient("/search")
    @Override
    public Map<String, Object> search(Map<String, Object> requestMap) throws IOException {
        String name = MapUtils.getString(requestMap, "name");
        String indexName = MapUtils.getString(requestMap, "indexName");
        List<AgentCard> agentCards = new ArrayList<>();
        SearchResponse<AgentCard> response = elasticsearchClient.search(
                s -> s.index(indexName)
                        .query(
                                q -> q.match(
                                        t -> t.field("name")
                                                .query(name)
                                )
                        )
                ,
                AgentCard.class
        );
        TotalHits total = response.hits().total();
        boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
        if (isExactResult) {
            log.info("There are {} results", total.value());
        } else {
            log.info("There are more than {} results", total.value());
        }
        List<Hit<AgentCard>> hits = response.hits().hits();
        for (Hit<AgentCard> hit : hits) {
            AgentCard agentCard = hit.source();
            agentCards.add(agentCard);
        }

        Map<String, Object> result = new HashMap<>();
        result.put("agentCards", agentCards);
        return result;
    }

    // 通用方法：将JsonpSerializable对象序列化为JSON
    private Object serializeToJson(Object jsonpObject) {
        try {
            if (jsonpObject == null) {
                return new JSONObject();
            }

            JacksonJsonpMapper mapper = new JacksonJsonpMapper();
            StringWriter writer = new StringWriter();
            JsonGenerator generator = mapper.jsonProvider().createGenerator(writer);

            if (jsonpObject instanceof co.elastic.clients.json.JsonpSerializable) {
                ((co.elastic.clients.json.JsonpSerializable) jsonpObject).serialize(generator, mapper);
            } else {
                // 处理不是JsonpSerializable的对象(如Map)
                mapper.serialize(jsonpObject, generator);
            }

            generator.close();

            // 解析为JSON对象并返回
            return JSON.parse(writer.toString());
        } catch (Exception e) {
            e.printStackTrace();
            return new JSONObject();
        }
    }

}
